﻿using lot.SDK;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace lot.Map
{
    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    [ComVisible(true)]
    public class ObjectForScriptingHelper
    {
        public delegate void polyoutAction();
        public event polyoutAction polyout;
        public void jsCallPolygon(object poly)
        {
                //CommonDefine.PolyInfo = poly;
                CommonDefine.PolyInfo = JsonConvert.DeserializeObject<List<point>>(poly.ToString());
        }

        public void check(object newPoint)
        {
            point point = JsonConvert.DeserializeObject<point>(newPoint.ToString());
            if (point != null && CommonDefine.PolyInfo != null)
            {
                bool inpoly = CalculationAlgorithm(CommonDefine.PolyInfo.ToArray(), point);
                if (!inpoly)
                {
                    polyout?.Invoke();
                }
            }
        }

        public bool CalculationAlgorithm(point[] polygon, point p)
        {
            point[] pts = polygon;//获取多边形点
            //112.58464,26.909432
            int N = pts.Length;
            var boundOrVertex = true; //如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
            var intersectCount = 0;//cross points count of x 
            var precision = 2e-10; //浮点类型计算时候与0比较时候的容差
            point p1, p2;//neighbour bound vertices
            p1 = pts[0];//left vertex        
            for (var i = 1; i <= N; ++i)
            {//check all rays            
                if (p.Equals(p1))
                {
                    return boundOrVertex;//p is an vertex
                }

                p2 = pts[i % N];//right vertex            
                if (p.lat < Math.Min(p1.lat, p2.lat) || p.lat > Math.Max(p1.lat, p2.lat))
                {//ray is outside of our interests                
                    p1 = p2;
                    continue;//next ray left point
                }

                if (p.lat > Math.Min(p1.lat, p2.lat) && p.lat < Math.Max(p1.lat, p2.lat))
                {//ray is crossing over by the algorithm (common part of)
                    if (p.lng <= Math.Max(p1.lng, p2.lng))
                    {//x is before of ray                    
                        if (p1.lat == p2.lat && p.lng >= Math.Min(p1.lng, p2.lng))
                        {//overlies on a horizontal ray
                            return boundOrVertex;
                        }

                        if (p1.lng == p2.lng)
                        {//ray is vertical                        
                            if (p1.lng == p.lng)
                            {//overlies on a vertical ray
                                return boundOrVertex;
                            }
                            else
                            {//before ray
                                ++intersectCount;
                            }
                        }
                        else
                        {//cross point on the left side                        
                            var xinters = (p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng;//cross point of lng                        
                            if (Math.Abs(p.lng - xinters) < precision)
                            {//overlies on a ray
                                return boundOrVertex;
                            }

                            if (p.lng < xinters)
                            {//before ray
                                ++intersectCount;
                            }
                        }
                    }
                }
                else
                {//special case when ray is crossing through the vertex                
                    if (p.lat == p2.lat && p.lng <= p2.lng)
                    {//p crossing over p2                    
                        var p3 = pts[(i + 1) % N]; //next vertex                    
                        if (p.lat >= Math.Min(p1.lat, p3.lat) && p.lat <= Math.Max(p1.lat, p3.lat))
                        {//p.lat lies between p1.lat & p3.lat
                            ++intersectCount;
                        }
                        else
                        {
                            intersectCount += 2;
                        }
                    }
                }
                p1 = p2;//next ray left point
            }
            if (intersectCount % 2 == 0)
            {//偶数在多边形外
                return false;
            }
            else
            { //奇数在多边形内
                return true;
            }
        }
    }
}
